package com.test;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.parser.lexparser.LexicalizedParser;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.AnnotationPipeline;
import edu.stanford.nlp.pipeline.POSTaggerAnnotator;
import edu.stanford.nlp.pipeline.TokenizerAnnotator;
import edu.stanford.nlp.pipeline.WordsToSentencesAnnotator;
import edu.stanford.nlp.time.TimeAnnotations;
import edu.stanford.nlp.time.TimeAnnotator;
import edu.stanford.nlp.time.TimeExpression;
import edu.stanford.nlp.time.SUTime.Temporal;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.util.CoreMap;

public class MeParser {

	private final String DAY_MONTH = "\\b([1][3-9]|[2][0-9]|3[01])[\\/-](0?[1-9]|1[0-2])([\\/-][0-9]{4})\\b";
	private final String SINGLE_DIGIT_DAY = "\\b(\\d{4}[\\/-]\\d[\\/-]\\d{2})\\b|\\b(\\d{4}[\\/-]\\d{2}[\\/-]\\d)\\b|\\b(\\d{4}[\\/-]\\d[\\/-]\\d)\\b|\\b(\\d[\\/-]\\d{2}[\\/-]\\d{4})\\b|\\b(\\d{2}[\\/-]\\d[\\/-]\\d{4})\\b|\\b(\\d[\\/-]\\d[\\/-]\\d{4})\\b";

	private LexicalizedParser lp = null;
	private AnnotationPipeline pipeline = null;

	public ArrayList<Calendar> dates;
	public Calendar start;
	public Calendar end;
	public ArrayList<String> phrases;
	public ArrayList<String> titles;
	public ArrayList<String> locations;

	public ArrayList<String> titleHistory = null;
	public ArrayList<String> locationHistory = null;

	public MeParser() {

		dates = new ArrayList<Calendar>();
		phrases = new ArrayList<String>();
		titles = new ArrayList<String>();
		locations = new ArrayList<String>();

		titleHistory = new ArrayList<String>();
		locationHistory = new ArrayList<String>();

		Properties props = new Properties();
		pipeline = new AnnotationPipeline();
		pipeline.addAnnotator(new TokenizerAnnotator(false));
		pipeline.addAnnotator(new WordsToSentencesAnnotator(false));
		pipeline.addAnnotator(new POSTaggerAnnotator(false));
		pipeline.addAnnotator(new TimeAnnotator("sutime", props));

		String parserModel = "edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz";
		lp = LexicalizedParser.loadModel(parserModel);
	}

	public void extractEvent(String input) {
		String[] lines = input.split("\n");

		for (String line : lines) {
			line = calibrateInput(line);
			line = extractDateTime(line);
			parseIt(line);
		}
		if (phrases != null && phrases.size() > 0) {
			for (int i = 0; i < phrases.size() && i < 4; i++) {
				titles.add(phrases.get(i));
			}
		}
		// learnFromDb();
	}

	// calibrate date and time format
	private String calibrateInput(String line) {

		Pattern p = Pattern.compile(DAY_MONTH);
		Matcher m = p.matcher(line);

		while (m.find()) {
			String oldPart = line.substring(m.start(), m.end());
			String[] tmp = oldPart.split("[\\/-]");
			if (tmp[0].length() == 1) {
				tmp[0] = "0" + tmp[0];
			}
			if (tmp[1].length() == 1) {
				tmp[1] = "0" + tmp[1];
			}
			String newPart = tmp[1] + "-" + tmp[0] + "-" + tmp[2];
			line = line.replace(oldPart, newPart);
		}

		p = Pattern.compile(SINGLE_DIGIT_DAY);
		m = p.matcher(line);

		while (m.find()) {
			String oldPart = line.substring(m.start(), m.end());
			String[] tmp = oldPart.split("[\\/-]");
			if (tmp[0].length() == 1) {
				tmp[0] = "0" + tmp[0];
			}
			if (tmp[1].length() == 1) {
				tmp[1] = "0" + tmp[1];
			}
			if (tmp[2].length() == 1) {
				tmp[2] = "0" + tmp[2];
			}
			String newPart = tmp[0] + "-" + tmp[1] + "-" + tmp[2];
			line = line.replace(oldPart, newPart);
		}
		return line;
	}

	// extract dates and time
	private String extractDateTime(String line) {

		Annotation annotation = new Annotation(line);

		Calendar today = Calendar.getInstance();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		String todayFormatted = formatter.format(today.getTime());

		annotation.set(CoreAnnotations.DocDateAnnotation.class, todayFormatted);
		pipeline.annotate(annotation);

		List<CoreMap> timexAnnsAll = annotation
				.get(TimeAnnotations.TimexAnnotations.class);

		System.out.println("input string: " + line + "\n");
		for (CoreMap cm : timexAnnsAll) {
			// List<CoreLabel> tokens = cm
			// .get(CoreAnnotations.TokensAnnotation.class);

			Temporal temporal = cm.get(TimeExpression.Annotation.class)
					.getTemporal();

			Calendar date = Calendar.getInstance();
			date.set(Calendar.MINUTE, 0);
			date.set(Calendar.SECOND, 0);
			String temporalStirng = temporal.toString();
			String temporalType = temporal.getTimexType().toString();
			String temporalDay = null;
			String temporalTime = null;

			if (temporalType.equals("TIME")) {

				String[] dayTimeArray = temporalStirng.split("T");
				if (dayTimeArray == null || dayTimeArray.length < 2) {
					continue;
				}
				temporalDay = dayTimeArray[0];
				temporalTime = dayTimeArray[1];

				String[] dayArray = temporalDay.split("-");
				if (dayArray == null || dayArray.length < 3) {
					continue;
				}
				// int length = dayArray.length;
				// for (int i = 0; i < length && i < 3; i++) {
				// if (isInteger(dayArray[i])) {
				// if (i == 0) {
				// date.set(Calendar.YEAR,
				// Integer.parseInt(dayArray[0]));
				// } else if (i == 1) {
				// date.set(Calendar.MONTH,
				// Integer.parseInt(dayArray[1]) - 1);
				// } else {
				// date.set(Calendar.DAY_OF_MONTH,
				// Integer.parseInt(dayArray[2]));
				// }
				// }
				// }
				if (isInteger(dayArray[0]) && isInteger(dayArray[1])
						&& isInteger(dayArray[2])) {
					date.set(Calendar.YEAR, Integer.parseInt(dayArray[0]));
					date.set(Calendar.MONTH, Integer.parseInt(dayArray[1]) - 1);
					date.set(Calendar.DAY_OF_MONTH,
							Integer.parseInt(dayArray[2]));
				} else {
					continue;
				}

				String[] timeArray = temporalTime.split(":");
				if (timeArray == null || timeArray.length < 2) {
					continue;
				}
				if (isInteger(timeArray[0]) && isInteger(timeArray[1])) {

					date.set(Calendar.HOUR_OF_DAY,
							Integer.parseInt(timeArray[0]));
					date.set(Calendar.MINUTE, Integer.parseInt(timeArray[1]));

					String tmp = cm.toString();
					dates.add(date);
					line = line.replace(tmp, "");
				}

			} else if (temporalType.equals("DATE")) {

				String[] dayArray = temporalStirng.split("-");
				if (dayArray == null || dayArray.length < 3) {
					continue;
				}

				// int length = dayArray.length;
				// for (int i = 0; i < length && i < 3; i++) {
				// if (isInteger(dayArray[i])) {
				// if (i == 0) {
				// date.set(Calendar.YEAR,
				// Integer.parseInt(dayArray[0]));
				// } else if (i == 1) {
				// date.set(Calendar.MONTH,
				// Integer.parseInt(dayArray[1]) - 1);
				// } else {
				// date.set(Calendar.DAY_OF_MONTH,
				// Integer.parseInt(dayArray[2]));
				// }
				// }
				// }
				//
				if (isInteger(dayArray[0]) && isInteger(dayArray[1])
						&& isInteger(dayArray[2])) {
					date.set(Calendar.YEAR, Integer.parseInt(dayArray[0]));
					date.set(Calendar.MONTH, Integer.parseInt(dayArray[1]) - 1);
					date.set(Calendar.DAY_OF_MONTH,
							Integer.parseInt(dayArray[2]));
				} else {
					continue;
				}

				String tmp = cm.toString();
				dates.add(date);
				line = line.replace(tmp, "");

			}
		}
		Calendar todayInstance = Calendar.getInstance();
		for (Calendar date : dates) {
			if (date.before(todayInstance)) {
				continue;
			} else if (start == null) {
				start = date;
			} else if (end == null) {
				end = date;
			} else {
				break;
			}
		}
		if (start != null && end != null && end.before(start)) {
			Calendar tmp = start;
			start = end;
			end = tmp;
		}
		return line;
	}

	private boolean isInteger(String input) {
		try {
			Integer.parseInt(input);
		} catch (NumberFormatException e) {
			return false;
		} catch (NullPointerException e) {
			return false;
		}
		return true;
	}

	private void parseIt(String line) {

		Tree parse = lp.parse(line);

		System.out.println("Tree:\n");
		parse.pennPrint();
		System.out.println("\n**********************************\n");

		for (Tree subtree : parse) {

			if (subtree.value().equals("VP")) {
				for (Tree child : subtree.children()) {
					if (child.value().equals("NP")
							|| child.value().equals("NN")) {

						List<Tree> leaves = subtree.getLeaves();
						String phrase = "";
						for (Tree leaf : leaves) {
							phrase = phrase + leaf.value() + " ";
						}
						phrase = phrase.replaceAll("-LRB- ", "(");
						phrase = phrase.replaceAll(" -RRB-", ")");
						phrase = phrase.trim();
						if (phrase.endsWith(":")) {
							phrase = phrase.substring(0, phrase.length() - 1);
						}
						phrases.add(phrase.trim());
						break;
					}
				}
			}

			if (subtree.value().equals("PP")) {
				for (Tree child : subtree.children()) {
					if (child.value().equals("NP")) {

						List<Tree> leaves = child.getLeaves();
						String location = "";
						for (Tree leaf : leaves) {
							location = location + leaf.value() + " ";
						}
						location = location.replaceAll("-LRB- ", "(");
						location = location.replaceAll(" -RRB-", ")");
						location = location.trim();
						if (location.endsWith(":")) {
							location = location.substring(0,
									location.length() - 1);
						}
						locations.add(location.trim());
					}
				}
			}

			if (subtree.value().equals("NP")) {

				boolean allNp = true;
				boolean nn = false;
				boolean np = false;
				boolean nnpAndCd = false;

				Tree[] children = subtree.children();

				for (int i = 0; i < children.length; i++) {

					String value = children[i].value();

					if (children.length == 2 && i + 1 < children.length
							&& value.equals("NNP")
							&& children[i + 1].value().equals("CD")) {
						nnpAndCd = true;
					}

					// switch (value) {
					//
					// case ",":
					// break;
					//
					// case "NP":
					// np = true;
					// break;
					//
					// case "CD":
					// allNp = false;
					// break;
					//
					// case "NN":
					// nn = true;
					// allNp = false;
					// break;
					//
					// default:
					// allNp = false;
					// break;
					// }

					if (value.equals(",")) {

					} else if (value.equals("NP")) {
						np = true;

					} else if (value.equals("CD")) {
						allNp = false;

					} else if (value.equals("NN")) {
						nn = true;
						allNp = false;

					} else {
						allNp = false;
					}

				}
				if (allNp || nnpAndCd) {

					List<Tree> leaves = subtree.getLeaves();
					String location = "";
					for (Tree leaf : leaves) {
						location = location + leaf.value() + " ";
					}
					location = location.replaceAll("-LRB- ", "(");
					location = location.replaceAll(" -RRB-", ")");
					location = location.trim();
					if (location.endsWith(":")) {
						location = location.substring(0, location.length() - 1);
					}
					locations.add(location.trim());

				} else if (nn || np) {

					List<Tree> leaves = subtree.getLeaves();
					String phrase = "";
					for (Tree leaf : leaves) {
						phrase = phrase + leaf.value() + " ";
					}
					phrase = phrase.replaceAll("-LRB- ", "(");
					phrase = phrase.replaceAll(" -RRB-", ")");
					phrase = phrase.trim();
					if (phrase.endsWith(":")) {
						phrase = phrase.substring(0, phrase.length() - 1);
					}
					phrases.add(phrase.trim());

				}
			}
		}
	}

	// private void learnFromDb() {
	// ArrayList<DBItem> history = AppUtil.App.dataService.retrieveTitles();
	// for (DBItem item : history) {
	// titleHistory.add(item.getName());
	//
	// }
	//
	// history = AppUtil.App.dataService.retrieveLoactions();
	// for (DBItem item : history) {
	// locationHistory.add(item.getName());
	// }
	// }

	// 0 for title, 1 for location
	private void merge(int type) {
		if (type == 0) {

		} else if (type == 1) {

		} else {

		}
	}

	public void clear() {

		dates.clear();
		phrases.clear();
		titles.clear();
		locations.clear();

	}

	public void testData() {

		System.out.println("\ntitle: ");
		for (String title : titles) {
			System.out.println(title);
		}

		System.out.println("\nstart: ");
		if (start != null) {
			System.out.println(start.getTime());
		}

		System.out.println("\nend: ");
		if (end != null) {
			System.out.println(end.getTime());
		}

		System.out.println("\nlocation: ");
		for (String location : locations) {
			System.out.println(location);
		}

		System.out.println("\ndate and time: ");
		for (int i = 0; i < dates.size(); i++) {
			System.out.println(dates.get(i).getTime());
		}

		System.out.println("\nphrases: ");
		for (String phrase : phrases) {
			System.out.println(phrase);
		}
	}
}
